package nancal.mp.config.filter

import nancal.mp.client.iam.IamCAuthApiClient
import nancal.mp.config.base.BaseFilter
import nancal.mp.db.redis.rer
import nancal.mp.findParameterValue
import nbcp.base.comm.BatchReader
import nbcp.base.extend.AsBooleanWithNull
import nbcp.base.extend.AsInt
import nbcp.base.utils.SpringUtil
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.cloud.gateway.filter.GatewayFilterChain
import org.springframework.cloud.gateway.filter.GlobalFilter
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import org.springframework.util.AntPathMatcher
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import java.util.*


@Configuration
@ConditionalOnProperty("app.iam", havingValue = "true", matchIfMissing = false)
class IamApiFilter : BaseFilter(), GlobalFilter, Ordered {


    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)

        //        private val executor = Executors.newFixedThreadPool(200);
        private val ALLOWED_PATHS: Set<String> = Collections.unmodifiableSet(
                HashSet<String>(
                        Arrays.asList("mp-oauth-api/oauth/user-info")
                )
        )

    }

    val iamCAuthApiClient by lazy {
        return@lazy SpringUtil.getBean<IamCAuthApiClient>()
    }


    override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain): Mono<Void> {
        //如果有 user-id
        if (exchange.request.getHeader("user-id").any() == false) {
            return chain.filter(exchange);
        }

        if (ALLOWED_PATHS.contains(exchange.request.uri.path)) {
            return chain.filter(exchange);
        }

        var needIam = exchange.request.findParameterValue("iam").AsBooleanWithNull()
        if (needIam == false) {
            return chain.filter(exchange);
        }


//        var ex: Throwable? = null;
//        var f01: CompletableFuture<Boolean> = CompletableFuture.supplyAsync({
//            FluxContext.init(exchange)
//            procExchange(exchange);
//        }, executor)
//                .handle { t, err ->
//                    if (err != null) {
//                        ex = err;
//                        return@handle false;
//                    }
//                    if (t == null || t == false) {
//                        return@handle false;
//                    }
//
//                    return@handle true
//                }


        var result = procExchange(exchange);
//        if (ex != null) {
//            exchange.response.rawStatusCode = 513;
//            logger.error(ex!!.message, ex);
//            return Mono.empty()
//        }

        if (result == false) {
//            exchange.response.rawStatusCode = 403;
            return Mono.empty()
        }
        return chain.filter(exchange)
    }

    private fun procExchange(exchange: ServerWebExchange): Boolean {
        var url = exchange.request.uri.path;
        var openNumber = rer.iam.apiOpenNumber.get().AsInt()

        var userId = exchange.request.getHeader("user-id")

        //如果精确匹配
        if (rer.iam.directApi(openNumber).isMember(url)) {
            //调用IAM接口
            var apply = iamCAuthApiClient.getAuthResult(
                    IamCAuthApiClient.AuthUrlDataModel(
                            url,
                            userId
                    )
            )
            if (apply.code != 0 || apply.data == null) {
                logger.warn("请求 http://mp-oauth-api/oauth/getAuthResult 接口错误! ${apply.msg}");
                exchange.response.rawStatusCode = 513;
                return false
            }

            if (apply.data == false) {
                logger.warn("请求 http://mp-oauth-api/oauth/getAuthResult 接口错误! ${apply.msg}");
                exchange.response.rawStatusCode = 403;
                return false
            } else {
                return true
            }
        }


        //看是否是模式匹配
        var matcher = AntPathMatcher();

        var matched = BatchReader.init { skip, take ->
            rer.iam.regexApi(openNumber).getListByIndex(skip, skip + take)
        }.firstOrNull {
            matcher.match(it, url)
        }



        if (matched.isNullOrEmpty()) {
            return true
        }

        //调用 IAM 接口
        var result = iamCAuthApiClient.getAuthResult(
                IamCAuthApiClient.AuthUrlDataModel(
                        url,
                        userId
                )
        )

        if (result.code != 0 || result.data == null) {
            exchange.response.rawStatusCode = 513;
            return false
        }

        if (result.data == false) {
            exchange.response.rawStatusCode = 403;
            return false
        }

        return true;
    }


    override fun getOrder(): Int {
        return Ordered.HIGHEST_PRECEDENCE + 2;
    }
}